package com.giteelou.antlr.ps.man;

import com.giteelou.antlr.ps.MyParser;
import com.giteelou.antlr.ps.MyParserBaseListener;
import com.giteelou.antlr.ps.man.symbol.Variable;
import com.giteelou.antlr.ps.man.type.PrimitiveType;
import com.giteelou.antlr.ps.man.type.Type;
import org.antlr.v4.runtime.Token;

/**
 * 扫描变量
 */
public class VariableScanner extends MyParserBaseListener {

    private final Semantics semantics;

    public VariableScanner(Semantics semantics) {
        this.semantics = semantics;
    }

    @Override
    public void enterVariableDeclaratorId(MyParser.VariableDeclaratorIdContext ctx) {
        // 变量声明
        if (ctx.IDENTIFIER() != null) {
            String name = ctx.IDENTIFIER().getText();
            Variable variable = new Variable(name, ctx);
            semantics.nodeSymbols.put(ctx, variable);
        }
    }

    @Override
    public void exitVariableDeclaration(MyParser.VariableDeclarationContext ctx) {
        // 给变量添加类型
        if (semantics.nodeTypes.containsKey(ctx.primitiveType())) {
            Type declaredType = semantics.nodeTypes.get(ctx.primitiveType());
            for (MyParser.VariableDeclaratorContext vCtx : ctx.variableDeclarators().variableDeclarator()) {
                MyParser.VariableDeclaratorIdContext idCtx = vCtx.variableDeclaratorId();
                Variable variable = (Variable) semantics.nodeSymbols.get(idCtx);
                variable.setType(declaredType);
                if (!semantics.variables.containsKey(variable.getName())) {
                    semantics.variables.put(variable.getName(), variable);
                } else {
                    Token token = idCtx.getStart();
                    semantics.errors.add("line " + token.getLine() + ":" + token.getStartIndex()
                            + " variable " + variable.getName() + " already declared.");
                    break;
                }
            }
        }
    }


    @Override
    public void exitPrimitiveType(MyParser.PrimitiveTypeContext ctx) {
        Type type = null;
        if (ctx.BOOLEAN() != null) {
            type = PrimitiveType.BOOLEAN;
        } else if (ctx.CHAR() != null) {
            type = PrimitiveType.CHAR;
        } else if (ctx.BYTE() != null) {
            type = PrimitiveType.BYTE;
        } else if (ctx.SHORT() != null) {
            type = PrimitiveType.SHORT;
        } else if (ctx.INT() != null) {
            type = PrimitiveType.INT;
        } else if (ctx.LONG() != null) {
            type = PrimitiveType.LONG;
        } else if (ctx.FLOAT() != null) {
            type = PrimitiveType.FLOAT;
        } else if (ctx.DOUBLE() != null) {
            type = PrimitiveType.DOUBLE;
        }
        if (type != null)
            semantics.nodeTypes.put(ctx, type);
    }

    @Override
    public void exitVariableInitializer(MyParser.VariableInitializerContext ctx) {
        // 冒泡
        Type type = semantics.nodeTypes.get(ctx.literal());
        if (type != null) {
            semantics.nodeTypes.put(ctx, type);
        }
    }

    @Override
    public void exitLiteral(MyParser.LiteralContext ctx) {
        Type type = null;
        if (ctx.DECIMAL_LITERAL() != null) {
            type = PrimitiveType.INT;
            if (ctx.DECIMAL_LITERAL().getText().toUpperCase().endsWith("L")) {
                type = PrimitiveType.LONG;
            }
        } else if (ctx.FLOAT_LITERAL() != null) {
            type = PrimitiveType.DOUBLE;
            if (ctx.FLOAT_LITERAL().getText().toUpperCase().endsWith("F")) {
                type = PrimitiveType.FLOAT;
            }
        } else if (ctx.CHAR_LITERAL() != null) {
            type = PrimitiveType.CHAR;
        } else if (ctx.BOOL_LITERAL() != null) {
            type = PrimitiveType.BOOLEAN;
        }
        if (type != null)
            semantics.nodeTypes.put(ctx, type);
    }
}
